home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 424_01 / ed_157 / move_word.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-11  |  12.9 KB  |  552 lines

  1. /*
  2.  * Copyright (C) 1992 by Rush Record (rhr@clio.rice.edu)
  3.  * 
  4.  * This file is part of ED.
  5.  * 
  6.  * ED is free software; you can redistribute it and/or modify it under the terms
  7.  * of the GNU General Public License as published by the Free Software Foundation.
  8.  * 
  9.  * ED is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  10.  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  11.  * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  12.  * 
  13.  * You should have received a copy of the GNU General Public License along with ED
  14.  * (see the file COPYING).  If not, write to the Free Software Foundation, 675
  15.  * Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17. #include "opsys.h"
  18.  
  19. #include <string.h>
  20.  
  21. #include "memory.h"
  22. #include "rec.h"
  23. #include "window.h"
  24. #include "ed_dec.h"
  25.  
  26. static Char word_table[256];
  27.  
  28. /******************************************************************************\
  29. |Routine: move_word
  30. |Callby: edit word_fill
  31. |Purpose: Moves the cursor a number of words forward or backward.
  32. |Arguments:
  33. |    repeat is the number of words to move.
  34. \******************************************************************************/
  35. void move_word(repeat)
  36. register Int repeat;
  37. {
  38.     register Uchar *c,*e;
  39.  
  40.     c = (Uchar *)&CURREC->data[CURBYT];
  41.     if(DIRECTION > 0)
  42.         while(repeat-- > 0)
  43.         {
  44.             if(CURREC == BASE)
  45.             {
  46.                 fix_display();
  47.                 WANTCOL = CURCOL = 1;
  48.                 abort_key();
  49.                 return;
  50.             }
  51.             if(CURBYT == CURREC->length)
  52.             {
  53.                 CURREC = CURREC->next;
  54.                 CURBYT = 0;
  55.                 c = (Uchar *)&CURREC->data[CURBYT];
  56.                 CURROW++;
  57.             }
  58.             else
  59.             {
  60.                 e = (Uchar *)&CURREC->data[CURREC->length];
  61.                 while(!word_table[*c] && c != e)    /* get into some delimiters */
  62.                     c++;
  63.                 if(c == e)    /* hit end of record */
  64.                     CURBYT = CURREC->length;
  65.                 else
  66.                 {
  67.                     c++;
  68.                     while(word_table[*c] && c != e)
  69.                         c++;
  70.                     e = (Uchar *)CURREC->data;
  71.                     CURBYT = c - e;
  72.                 }
  73.             }
  74.         }
  75.     else    /* direction is backwards */
  76.         while(repeat-- > 0)
  77.         {
  78.             if(!CURBYT)
  79.             {
  80.                 if(CURREC->prev == BASE)
  81.                 {
  82.                     fix_display();
  83.                     WANTCOL = CURCOL = 1;
  84.                     abort_key();
  85.                     return;
  86.                 }
  87.                 CURREC = CURREC->prev;
  88.                 CURBYT = CURREC->length;
  89.                 c = (Uchar *)&CURREC->data[CURBYT];
  90.                 CURROW--;
  91.             }
  92.             else
  93.             {
  94.                 e = (Uchar *)CURREC->data;
  95.                 c--;
  96.                 while(word_table[*c] && c != e)    /* get into some non-delimiters */
  97.                     c--;
  98.                 if(c == e)    /* hit end of record */
  99.                     CURBYT = 0;
  100.                 else
  101.                 {
  102.                     c--;
  103.                     while(!word_table[*c] && c != e)      /* find a delimiter */
  104.                         c--;
  105.                     if(c == e)
  106.                     {
  107.                         if(word_table[*c])
  108.                             c++;
  109.                     }
  110.                     else
  111.                         c++;
  112.                     CURBYT = c - e;
  113.                 }
  114.             }
  115.         }
  116.     CURCOL = get_column(CURREC,CURBYT);
  117.     WANTCOL = CURCOL;
  118.     fix_display();
  119. }
  120.  
  121. /******************************************************************************\
  122. |Routine: find_word
  123. |Callby: edit word_fill
  124. |Purpose: Does what move_word does, without actually moving the cursor. Instead,
  125. |         it returns the new position of the cursor (if it had actually moved)
  126. |         as an offset from the current position.
  127. |Arguments:
  128. |    prepeat is the number of words to (figuratively) move.
  129. \******************************************************************************/
  130. Int find_word(prepeat)
  131. register Int prepeat;
  132. {
  133.     register Uchar *c,*e;
  134.     rec_ptr currec;
  135.     register Int repeat,curbyt;
  136.     Int offset;
  137.  
  138.     currec = CURREC;
  139.     curbyt = CURBYT;
  140.     c = (Uchar *)&currec->data[curbyt];
  141.     offset = 0;
  142.     if(prepeat > 0)
  143.     {
  144.         repeat = prepeat;
  145.         while(repeat-- > 0)
  146.         {
  147.             if(currec == BASE)
  148.                 return(0);
  149.             if(curbyt == currec->length)
  150.             {
  151.                 currec = currec->next;
  152.                 curbyt = 0;
  153.                 c = (Uchar *)&currec->data[curbyt];
  154.                 offset++;
  155.             }
  156.             else
  157.             {
  158.                 e = (Uchar *)&currec->data[currec->length];
  159.                 while(!word_table[*c] && c != e)    /* get into some delimiters */
  160.                 {
  161.                     c++;
  162.                     offset++;
  163.                 }
  164.                 if(c == e)    /* hit end of record */
  165.                     curbyt = currec->length;
  166.                 else
  167.                 {
  168.                     c++;
  169.                     offset++;
  170.                     while(word_table[*c] && c != e)
  171.                     {
  172.                         c++;
  173.                         offset++;
  174.                     }
  175.                     e = (Uchar *)currec->data;
  176.                     curbyt = c - e;
  177.                 }
  178.             }
  179.         }
  180.     }
  181.     else    /* direction is backwards */
  182.     {
  183.         repeat = -prepeat;
  184.         while(repeat-- > 0)
  185.         {
  186.             if(!curbyt)
  187.             {
  188.                 if(currec->prev == BASE)
  189.                     return(0);
  190.                 currec = currec->prev;
  191.                 curbyt = currec->length;
  192.                 c = (Uchar *)&currec->data[curbyt];
  193.                 offset--;
  194.             }
  195.             else
  196.             {
  197.                 e = (Uchar *)currec->data;
  198.                 c--;
  199.                 offset--;
  200.                 while(word_table[*c] && c != e)    /* get into some non-delimiters */
  201.                 {
  202.                     c--;
  203.                     offset--;
  204.                 }
  205.                 if(c == e)    /* hit end of record */
  206.                     curbyt = 0;
  207.                 else
  208.                 {
  209.                     c--;
  210.                     offset--;
  211.                     while(!word_table[*c] && c != e)      /* find a delimiter */
  212.                     {
  213.                         c--;
  214.                         offset--;
  215.                     }
  216.                     if(c != e)
  217.                     {
  218.                         c++;
  219.                         offset++;
  220.                     }
  221.                     curbyt = c - e;
  222.                 }
  223.             }
  224.         }
  225.     }
  226.     return(offset);
  227. }
  228.  
  229. /******************************************************************************\
  230. |Routine: find_word_string
  231. |Callby: inquire
  232. |Purpose: Finds the beginning of a word in the user buffer used in
  233. |         the inquire routine. Returns the index in the buffer of the word's
  234. |         first character.
  235. |Arguments:
  236. |    repeat is the number of words to (figuratively) back up.
  237. |    string is the user buffer.
  238. |    length is the length of the data in string.
  239. |    cursor is the cursor position in the buffer.
  240. |    direct is the search direction (-1 = backward, 1 = forward).
  241. \******************************************************************************/
  242. Int find_word_string(repeat,string,length,cursor,direct)
  243. register Int repeat;
  244. Char *string;
  245. Int length,cursor,direct;
  246. {
  247.     register Uchar *c,*e;
  248.  
  249.     if(direct == -1)
  250.     {
  251.         if(!cursor)
  252.             return(0);
  253.         e = (Uchar *)string;
  254.         c = e + cursor - 1;
  255.         while(repeat--)
  256.         {
  257.             while(word_table[*c])    /* get into some non-delimiters */
  258.                 if(c-- == e)
  259.                     return(0);
  260.             while(!word_table[*c])      /* find a delimiter */
  261.                 if(c-- == e)
  262.                     return(0);
  263.         }
  264.         return(((Char *)c) - string + 1);
  265.     }
  266.     else
  267.     {
  268.         c = (Uchar *)string + cursor;
  269.         e = (Uchar *)string + length;
  270.         while(repeat--)
  271.         {
  272.             while(!word_table[*c] && c != e)    /* get into some delimiters */
  273.                 c++;
  274.             if(c == e)    /* hit end of record */
  275.                 break;
  276.             c++;
  277.             while(word_table[*c] && c != e)
  278.                 c++;
  279.             if(c == e)    /* hit end of record */
  280.                 break;
  281.         }
  282.         return(((Char *)c) - string);
  283.     }
  284. }
  285.  
  286. /******************************************************************************\
  287. |Routine: init_word_table
  288. |Callby: restore_par set_param word_fill
  289. |Purpose: Initializes the word delimiter list.
  290. |Arguments:
  291. |    ndelim is the number of word delimiters.
  292. |    delims is the array of word delimiters.
  293. \******************************************************************************/
  294. void init_word_table(ndelim,delims)
  295. Int ndelim;
  296. Uchar *delims;
  297. {
  298.     memset(word_table,0,256);
  299.     for(;ndelim > 0;ndelim--)
  300.         word_table[*delims++] = 1;
  301. }
  302.  
  303. /******************************************************************************\
  304. |Routine: wordtable
  305. |Callby: match_search
  306. |Purpose: Returns the address of the current word-delimiter table.
  307. |Arguments:
  308. |    none
  309. \******************************************************************************/
  310. Char *wordtable()
  311. {
  312.     return(word_table);
  313. }
  314.  
  315. /******************************************************************************\
  316. |Routine: get_word_start
  317. |Callby: match_search
  318. |Purpose: Finds the next word. Returns 0 on failure. Returns 1 if we are sitting
  319. |         on a word, else finds a beginning of a word in the forward direction.
  320. |Arguments:
  321. |    base is the record queue base.
  322. |    pr is the current record pointer.
  323. |    cur is the starting position for the word search.
  324. |    length is the returned length of the word.
  325. |    poffset is the search offset, which can end up getting modified here.
  326. \******************************************************************************/
  327. Int get_word_start(base,pr,pcur,length,poffset)
  328. rec_ptr base,*pr;
  329. Int *pcur,*length;
  330. Int *poffset;
  331. {
  332.     rec_ptr r;
  333.     Int cur,end;
  334.     Int offset;
  335.     
  336.     r = *pr;
  337.     cur = *pcur;
  338.     if(poffset)
  339.         offset = *poffset;
  340.     else
  341.         offset = 0;
  342.     if(cur >= r->length)
  343.         goto advance;
  344.     if(r->length && cur && !word_table[(Uchar)r->data[cur]])
  345.         if(word_table[(Uchar)r->data[cur - 1]])
  346.             goto report;    /* we are already at the beginning of a word */
  347.     if(cur)    /* if we are not at the beginning of a line... */
  348.     {
  349.         if(!word_table[(Uchar)r->data[cur]])    /* if we are on a non-delimiter... */
  350.         {
  351.             if(!word_table[(Uchar)r->data[cur - 1]])    /* and the previous character is a non-delimiter... */
  352.             {    /* we need to advance to the end of the current word before advancing */
  353.                 while(cur < r->length && !word_table[(Uchar)r->data[cur]])    /* find a delimiter */
  354.                 {
  355.                     cur++;
  356.                     offset++;
  357.                 }
  358. advance:
  359.                 while(cur < r->length && word_table[(Uchar)r->data[cur]])    /* find a non-delimiter */
  360.                 {
  361.                     cur++;
  362.                     offset++;
  363.                 }
  364.                 if(cur >= r->length)
  365.                 {
  366.                     if(r == base || (r = r->next) == base)
  367.                         return(0);
  368.                     cur = 0;
  369.                     offset++;
  370.                     goto advance;
  371.                 }
  372.             }
  373.         }
  374.         else
  375.             goto advance;
  376.     }
  377.     else
  378.         if(!r->length || word_table[(Uchar)r->data[0]])    /* we are at the beginning of a line, and the first char is a delimiter */
  379.             goto advance;
  380. /* cur is now at the beginning of a word */
  381. report:
  382.     end = cur + 1;
  383.     offset++;
  384.     while(end < r->length && !word_table[(Uchar)r->data[end]])
  385.     {
  386.         end++;
  387.         offset++;
  388.     }
  389.     *pr = r;
  390.     *pcur = cur;
  391.     *length = end - cur;
  392.     if(poffset)
  393.         *poffset = offset;
  394.     return(1);
  395. }
  396.  
  397. /******************************************************************************\
  398. |Routine: get_word_end
  399. |Callby: match_search
  400. |Purpose: Finds the next end of a word. Returns 0 on failure. Returns 1 if we
  401. |         are sitting on a wordend, else finds a wordend in the backward
  402. |         direction.
  403. |Arguments:
  404. |    base is the record queue base.
  405. |    pr is the current record pointer.
  406. |    cur is the starting position for the word search.
  407. |    length is the returned length of the word.
  408. |    poffset is the search offset, which can end up getting modified here.
  409. \******************************************************************************/
  410. Int get_word_end(base,pr,pcur,length,poffset)
  411. rec_ptr base,*pr;
  412. Int *pcur,*length;
  413. Int *poffset;
  414. {
  415.     rec_ptr r;
  416.     Int cur,end;
  417.     Int offset;
  418.     
  419.     r = *pr;
  420.     cur = *pcur;
  421.     if(poffset)
  422.         offset = *poffset;
  423.     else
  424.     {
  425.         if(!cur)    /* search string must be only one record, and we have hit the beginning of it */
  426.             return(0);
  427.         offset = 0;
  428.     }
  429. /* if we are at <end>, just back up */
  430.     if(poffset && r == base)
  431.     {
  432.         if((r = r->prev) == base)
  433.             return(0);    /* empty file */
  434.         cur = r->length;
  435.         offset--;
  436.     }
  437.     else    /* find a delimiter, going backwards */
  438.     {
  439.         if(cur < r->length)    /* if cur is equal to r->length, we are on a virtual delimiter, no need to look for one */
  440.             while(!word_table[(Uchar)r->data[cur]])
  441.             {
  442.                 if(--cur <= 0)    /* we hit the start of the record, which can never be a wordend */
  443.                 {
  444.                     while((r = r->prev) != base)
  445.                     {
  446.                         if((end = r->length))
  447.                         {
  448.                             while(end--)
  449.                                 if(!word_table[(Uchar)r->data[end]])
  450.                                     break;
  451.                             if(end >= 0)
  452.                                 break;
  453.                         }
  454.                         offset -= r->length + 1;
  455.                     }
  456.                     if(r == base)
  457.                         return(0);    /* cannot match at beginning of file */
  458.                     cur = r->length - 1;
  459.                     offset -= 2;
  460.                     break;
  461.                 }
  462.                 offset--;
  463.             }
  464.         else
  465.         {
  466.             cur--;
  467.             offset--;
  468.         }
  469.     }
  470. /* now find a non-delimiter. this is the wordend - 1 */
  471.     while(word_table[(Uchar)r->data[cur]])
  472.     {
  473.         if(--cur < 0)
  474.         {
  475.             if((r = r->prev) == base)
  476.                 return(0);
  477.             cur = r->length - 1;
  478.             offset--;
  479.         }
  480.         offset--;
  481.     }
  482. /* find the character before the beginning of this word */
  483.     end = cur + 1;
  484.     while(!word_table[(Uchar)r->data[cur]])
  485.     {
  486.         offset--;
  487.         if(--cur < 0)
  488.             break;
  489.     }
  490.     cur++;
  491.     offset++;
  492. /* cur is now at the beginning of a word */
  493.     *pr = r;
  494.     *pcur = cur;
  495.     *length = end - cur;
  496.     if(poffset)
  497.         *poffset = offset;
  498.     return(1);
  499. }
  500.  
  501. /******************************************************************************\
  502. |Routine: on_a_word
  503. |Callby: match_search
  504. |Purpose: Returns whether or not the specified position is at the start of a
  505. |         word.
  506. |Arguments:
  507. |    rec is the record.
  508. |    byt is the byte.
  509. \******************************************************************************/
  510. Int on_a_word(rec,byt)
  511. rec_ptr rec;
  512. Int byt;
  513. {
  514.     if(byt >= rec->length)
  515.         return(0);
  516.     if(!byt)
  517.     {
  518.         if(!word_table[(Uchar)rec->data[0]])
  519.             return(1);
  520.         return(0);
  521.     }
  522.     if(word_table[(Uchar)rec->data[byt]])
  523.         return(0);
  524.     if(!word_table[(Uchar)rec->data[byt - 1]])
  525.         return(0);
  526.     return(1);
  527. }
  528.  
  529. /******************************************************************************\
  530. |Routine: on_a_wordend
  531. |Callby: match_search
  532. |Purpose: Returns whether or not the specified position is past the end of a
  533. |         word.
  534. |Arguments:
  535. |    rec is the record.
  536. |    byt is the byte.
  537. \******************************************************************************/
  538. Int on_a_wordend(rec,byt)
  539. rec_ptr rec;
  540. Int byt;
  541. {
  542.     if(!byt)    /* beginning of record is never a wordend */
  543.         return(0);
  544.     if(byt < rec->length)
  545.         if(!word_table[(Uchar)rec->data[byt]])    /* must be on a delimiter */
  546.             return(0);
  547.     if(!word_table[(Uchar)rec->data[byt - 1]])
  548.         return(1);
  549.     return(0);
  550. }
  551.  
  552.